/*
 * 上海远境文化传媒有限公司 版权所有
 */
package facade;

import cache.CacheHelper;
import ext.auth.UserAuthHelper;
import facade.base.CorpFacade;
import helper.GlobalConfig;
import models.base.Corp;
import models.base.EntityProp;
import models.base.AdminUser;
import models.enums.ClientType;
import models.enums.OpenIdSource;
import play.Logger;
import play.Play;
import play.mvc.Http;
import util.play.RequestUtility;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 应用级别的上下文，使用ThreadLocal模式实现统一的场景数据设置与获取.
 */
public final class AppContext {

    private final static ThreadLocal<AdminUser> _currentUser = new ThreadLocal<>();
    private final static ThreadLocal<Corp> _currentCorp = new ThreadLocal<>();

    private final static ThreadLocal<Boolean> _currentPatchMode = new ThreadLocal<>();

    /**
     * TODO: 风险 - 如果大量公司使用，可能会内存满，修改成有上限的Map
     */
    private final static Map<String, String> _globalConfigMap = new ConcurrentHashMap<>();

    /**
     * 当前API接口来源.
     */
    private final static ThreadLocal<OpenIdSource> _currentApiPlatform = new ThreadLocal<>();
    private final static ThreadLocal<ClientType>   _currentClientType  = new ThreadLocal<>();

    public static void setUsr(AdminUser user) {
        _currentUser.set(user);
    }

    public static void setCorp(Corp corp) {
        _currentCorp.set(corp);
    }

    public static void setClientType(ClientType clientType) {
        _currentClientType.set(clientType);
    }

    public static void setApiPlatform(OpenIdSource openIdSource) {
        _currentApiPlatform.set(openIdSource);
    }

    /**
     * 在Controller中使用WexinCpAuth可以得到当前用户.
     */
    public static AdminUser currentUser() {
        return _currentUser.get();
    }

    public static AdminUser currentPersistentUser() {
        if (_currentUser.get() != null && _currentUser.get().id != null) {
            return AdminUser.findById(_currentUser.get().id);
        }
        return null;
    }

    public static Corp currentPersistentCorp() {
        if (_currentCorp.get() != null && _currentCorp.get().id != null) {
            return Corp.findById(_currentCorp.get().id);
        }
        return null;
    }


    public static Corp currentCorp() {
        return _currentCorp.get();
    }

    public static OpenIdSource getApiPlatform() {
        if (_currentApiPlatform.get() == null) {
            _currentApiPlatform.set(UserAuthHelper.getCurrentApiPlatform());
        }
        return _currentApiPlatform.get();
    }

    public static ClientType getClientType() {
        if (_currentClientType.get() == null) {
            _currentClientType.set(UserAuthHelper.getCurrentClientType());
        }
        return _currentClientType.get();
    }

    /**
     * 按key读取配置.
     * 先读取公司级，如果没有，就返回配置文件级别.
     */
    public static String getGlobalConfig(String key) {
        // 使用上下文中的公司.
        Corp corp = AppContext.currentCorp();
        return getGlobalConfig(corp, key, null);
    }

    public static String getGlobalConfig(String key, String defaultValue) {
        // 使用上下文中的公司.
        Corp corp = AppContext.currentCorp();
        return getGlobalConfig(corp, key, defaultValue);
    }

    public static String getGlobalConfig(Corp corp, String key) {
        return getGlobalConfig(corp, key, null);
    }

    /**
     * 读取配置，先公司再全局.
     * 内存缓存一下配置.
     */
    public static String getGlobalConfig(Corp corp, String key, String defaultValue) {
        if (corp != null) {
            return CacheHelper.getCache("GlobalConfig_" + corp.id + "_" + key, () -> {
                String value1 = EntityProp.getKeyValue(corp.id, key);
                if (value1 != null) {
                    return value1;
                }
                return Play.configuration.getProperty(key, defaultValue);
            });
        }
        return Play.configuration.getProperty(key, defaultValue);
    }

    public static boolean existsCorpConfig(Corp corp, String key) {
        return corp != null && EntityProp.getByKey(corp.id, key) != null;
    }

    /**
     * 读取公司配置.
     */
    public static String getCorpConfig(Corp corp, String key) {
        return getCorpConfig(corp, key, null);
    }
    public static String getCorpConfig(Corp corp, String key, String defaultValue) {
        if (corp != null) {
            return CacheHelper.getCache("CorpConfig_" + corp.id + "_" + key, () -> {
                String value1 = EntityProp.getKeyValue(corp.id, key);
                Logger.info("LOG06763: value1 = " + value1);
                if (value1 != null) {
                    return value1;
                }
                return defaultValue;
            });
        }
        return defaultValue;
    }

    private static void removeGlobalConfigFromMapOrMethod(String corpId, String key) {
        CacheHelper.delete("GlobalConfig_" + corpId + "_" + key);
    }


    public static void setGlobalConfig(Corp corp, String key, String value) {
        EntityProp.setKeyValue(corp.id, key, value);
        removeGlobalConfigFromMapOrMethod(corp.id, key);
        CorpFacade.clearCorpCache(corp);
    }

    /**
     * 应用模式： 测试模式.
     */
    public static boolean runningInTestMode() {
        return "test".equals(GlobalConfig.APP_MODE);
    }

    /**
     * 应用模式： 生产模式。
     * 安全起见，非 test 都是生产模式
     */
    public static boolean runningInProdMode() {
        return !runningInTestMode();
    }

    /**
     * 开发本地模式.
     */
    public static boolean isLocalDev(Http.Request request) {
        return Play.mode.isDev() && request != null && (request.domain.contains("localhost") || request.domain.contains("127.0.0.1"));
    }

    /**
     * 当前是否是PatchMode
     * 只在request.method==PATCH时返回true.
     */
    public static boolean patchMode() {
        if (_currentPatchMode.get() == null) {
            if (Http.Request.current() != null) {
                // 先检查Header
                String methodName = RequestUtility.getHeaderIgnoreCase("X-Request-Method");
                if ("PATCH".equals(methodName)) {
                    _currentPatchMode.set(Boolean.TRUE);
                } else {
                    _currentPatchMode.set("PATCH".equals(Http.Request.current().method));
                }
            } else {
                _currentPatchMode.set(Boolean.FALSE);
            }
        }
        return _currentPatchMode.get();
    }

    /**
     * 清除上下文.
     */
    public static void cleanUp() {
        _currentUser.remove();
        _currentCorp.remove();
        _currentApiPlatform.remove();
        _currentClientType.remove();
        _currentPatchMode.remove();
    }

}
